import logging
from typing import Annotated, Optional

from fastapi import APIRouter, Body, Form, Query, Request
from jose import ExpiredSignatureError

from app.api.deps import AuthServiceDep, CaptchaServiceDep, TokenDep
from app.core import settings
from app.database.db import SessionDep
from app.database.redis import RedisDep
from app.enums.result_code import ResultCode
from app.exceptions.base import AppException
from app.schemas.auth import Captcha, Token
from app.schemas.base import Response
from app.utils.log_api_call import log

WxMiniAppPhoneLoginDTO = object
WxMiniAppCodeLoginDTO = object

logger = logging.getLogger(__name__)

router = APIRouter(prefix=f"{settings.API_V1_STR}/auth", tags=["01.认证中心"])


@router.get("/captcha", response_model=Response[Captcha], summary="获取验证码", description="获取图形验证码信息")
async def get_captcha(captcha_service: CaptchaServiceDep) -> Response[Captcha]:
    """
    获取验证码
    """
    try:
        captcha = await captcha_service.generate_captcha()
        return Response[Captcha](data=captcha)
    except Exception as e:
        raise AppException(message="获取验证码失败") from e


@router.post("/login", response_model=Response[Token], summary="账号密码登录", description="使用用户名和密码进行登录")
@log(content="登录", module="登录")
async def login(
    request: Request,
    auth_service: AuthServiceDep,
    captcha_service: CaptchaServiceDep,
    username: str = Form(..., min_length=2, max_length=50, description="用户名", example="admin"),
    password: str = Form(..., min_length=6, max_length=100, description="密码", example="123456"),
    captcha_key: Optional[str] = Form(None, alias="captchaKey", description="验证码key"),
    captcha_code: Optional[str] = Form(None, alias="captchaCode", description="验证码"),
) -> Response[Token]:
    """
    账号密码登录
    """
    try:
        if settings.CAPTCHA_ENABLED:
            if not captcha_key or not captcha_code:
                return Response.failed(result_code=ResultCode.USER_VERIFICATION_CODE_EMPTY)

            # 验证验证码
            if not await captcha_service.verify_captcha(captcha_key, captcha_code):
                return Response.failed(result_code=ResultCode.USER_VERIFICATION_CODE_ERROR)

        token = await auth_service.login(username, password)
        return Response[Token](data=token)
    except AppException as e:
        raise AppException(message="登录失败") from e


@router.post(
    "/login/sms",
    response_model=Response[Token],
    summary="短信验证码登录",
    description="使用手机号和短信验证码进行登录",
)
@log(content="短信验证码登录", module="登录")
async def login_by_sms(
    request: Request,
    mobile: Annotated[str, Query(..., description="手机号", example="18812345678")],
    code: Annotated[str, Query(..., description="验证码", example="1234")],
    session: SessionDep,
    redis: RedisDep,
) -> Response[Token]:
    """
    短信验证码登录
    """
    pass


@router.post(
    "/sms/code",
    response_model=Response[None],
    summary="发送登录短信验证码",
    description="向指定手机号发送用于登录的短信验证码",
)
async def send_login_verify_code(
    mobile: Annotated[str, Query(..., description="手机号", example="18812345678")],
    session: SessionDep,
    redis: RedisDep,
) -> Response[None]:
    """
    发送登录短信验证码
    """
    pass


@router.post(
    "/login/wechat",
    response_model=Response[Token],
    summary="微信授权登录(Web)",
    description="使用微信授权码进行 Web 端登录",
)
@log(content="微信登录", module="登录")
async def login_by_wechat(
    request: Request,
    code: Annotated[str, Query(..., description="微信授权码", example="code")],
    session: SessionDep,
    redis: RedisDep,
) -> Response[Token]:
    """
    微信授权登录(Web)
    """
    pass


@router.post(
    "/wx/miniapp/code-login",
    response_model=Response[Token],
    summary="微信小程序登录(Code)",
    description="微信小程序通过临时登录凭证 code 登录",
)
async def login_by_wx_mini_app_code(
    login_dto: Annotated[WxMiniAppCodeLoginDTO, Body(..., description="微信小程序 Code 登录数据传输对象")],
    session: SessionDep,
    redis: RedisDep,
) -> Response[Token]:
    """
    微信小程序登录(Code)
    """
    pass


@router.post(
    "/wx/miniapp/phone-login",
    response_model=Response[Token],
    summary="微信小程序登录(手机号)",
    description="微信小程序通过加密的手机号信息登录",
)
async def login_by_wx_mini_app_phone(
    login_dto: Annotated[WxMiniAppPhoneLoginDTO, Body(..., description="微信小程序手机号登录数据传输对象")],
    session: SessionDep,
    redis: RedisDep,
) -> Response[Token]:
    """
    微信小程序登录(手机号)
    """
    pass


@router.delete(
    "/logout", response_model=Response[None], summary="退出登录", description="当前用户退出登录，清除认证信息"
)
@log(content="退出登录", module="登录")
async def logout(request: Request, auth_service: AuthServiceDep, token: TokenDep) -> Response[None]:
    """
    退出登录
    """
    try:
        await auth_service.logout(token.credentials)
    except ExpiredSignatureError:
        logger.warning("Token has expired, no need to revoke.")
    except Exception as e:
        raise AppException(message=f"Logout failed: {str(e)}") from e
    return Response.success()


@router.post(
    "/refresh-token", response_model=Response[Token], summary="刷新令牌", description="使用刷新令牌获取新的访问令牌"
)
async def refresh_token(
    auth_service: AuthServiceDep,
    refresh_token: Annotated[str, Query(..., description="刷新令牌", example="xxx.xxx.xxx")],
) -> Response[Token]:
    """
    刷新令牌
    """
    try:
        token = await auth_service.refresh_token(refresh_token)
        return Response[Token](data=token)
    except Exception as e:
        raise AppException(message=f"刷新令牌失败: {str(e)}") from e
